package com.zackeus.xupdate.factory.impl;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.liulishuo.okdownload.DownloadTask;
import com.liulishuo.okdownload.OkDownload;
import com.liulishuo.okdownload.core.cause.EndCause;
import com.liulishuo.okdownload.core.cause.ResumeFailedCause;
import com.liulishuo.okdownload.core.listener.DownloadListener1;
import com.liulishuo.okdownload.core.listener.assist.Listener1Assist;
import com.zackeus.common.utils.ObjectUtils;
import com.zackeus.xupdate.entity.LibraryUpdateEntity;
import com.zackeus.xupdate.factory.IUpdateDownloader;
import com.zackeus.xupdate.listener.OnFileDownloadListener;

/**
 * 默认版本更新下载器
 * @name: DefaultUpdateDownloader
 * @author: zz
 * @date: 2022/12/9
 */
public class DefaultUpdateDownloader implements IUpdateDownloader {

    /* 回调频率 */
    private final int callbackProcess;
    private int taskId;

    public DefaultUpdateDownloader() {
        this(100);
    }

    public DefaultUpdateDownloader(int callbackProcess) {
        this.callbackProcess = callbackProcess;
    }

    /**
     * 构建下载任务
     * @param url       下载链接
     * @param fileDir   文件目录
     * @param fileName  文件名
     * @param tag       任务标识 用于断点下载
     * @return
     */
    private DownloadTask createTask(@NonNull String url, @NonNull String fileDir, @NonNull String fileName, @Nullable Object tag) {
        DownloadTask.Builder builder = new DownloadTask.Builder(url, fileDir, fileName)
                /* 设置下载文件名，没提供的话先看 response header ，再看 url path(即启用下面那项配置) */
                .setFilename(fileName)
                /* 是否使用 response header or url path 作为文件名，此时会忽略指定的文件名，默认false */
                .setFilenameFromResponse(Boolean.FALSE)
                /* 如果文件已经下载完成，再次下载时，是否忽略下载，默认为true(忽略)，设为false会从头下载 */
                .setPassIfAlreadyCompleted(Boolean.TRUE)
                /* 需要用几个线程来下载文件，默认根据文件大小确定；如果文件已经 split block，则设置后无效 */
                .setConnectionCount(1)
                /* 在获取资源长度后，设置是否需要为文件预分配长度，默认false */
                .setPreAllocateLength(Boolean.FALSE)
                /* 通知调用者的频率，避免anr，默认3000 ms */
                .setMinIntervalMillisCallbackProcess(this.callbackProcess)
                /* 是否只允许wifi下载，默认为false */
                .setWifiRequired(Boolean.FALSE)
                /* 是否在主线程通知调用者，默认为true */
                .setAutoCallbackToUIThread(Boolean.TRUE)
                /* 设置优先级，默认值是0，值越大下载优先级越高 */
                .setPriority(0);
        /* Accept-Encoding 解决download onProgress 回调 total 为0 */
        builder.addHeader("Accept-Encoding", "*");

        DownloadTask task = builder.build();
        if (ObjectUtils.isNotNull(tag)) {
            /* 设置标识 用于断点下载 */
            task.setTag(tag);
        }
        this.taskId = task.getId();
        return task;
    }

    @Override
    public void startDownload(@NonNull LibraryUpdateEntity entity, @Nullable OnFileDownloadListener downloadListener) {
        DownloadTask task = createTask(entity.getUrl(), entity.getFileDir(), entity.getFileName(), entity.getEncrypt());

        task.enqueue(new DownloadListener1() {
            @Override
            public void taskStart(@NonNull DownloadTask task, @NonNull Listener1Assist.Listener1Model model) {
                if (downloadListener != null) {
                    downloadListener.onStart();
                }
            }

            @Override
            public void retry(@NonNull DownloadTask task, @NonNull ResumeFailedCause cause) {}

            @Override
            public void connected(@NonNull DownloadTask task, int blockCount, long currentOffset, long totalLength) {}

            @Override
            public void progress(@NonNull DownloadTask task, long currentOffset, long totalLength) {
                if (downloadListener != null) {
                    downloadListener.onProgress(currentOffset, totalLength);
                }
            }

            @Override
            public void taskEnd(@NonNull DownloadTask task, @NonNull EndCause cause, @Nullable Exception realCause, @NonNull Listener1Assist.Listener1Model model) {
                if (downloadListener == null) {
                    return;
                }

                if (ObjectUtils.isNotEmpty(realCause)) {
                    downloadListener.onError(realCause);
                } else {
                    downloadListener.onCompleted(task.getFile());
                }
            }
        });
    }

    @Override
    public void cancelDownload() {
        OkDownload.with().downloadDispatcher().cancel(this.taskId);
        OkDownload.with().breakpointStore().remove(this.taskId);
    }
}
